package jflowmap.model.ontology;

import java.util.Set;

import jflowmap.model.graph.Graph;

import com.google.common.collect.Sets;


public class GraphBuilder {

	private Set<Dimension> sources;
	private Set<Dimension> targets;
	private Set<Dimension> values;
	
	private final Context context;
	
	
	public Graph build (final String name) {
		Graph graph = new Graph(context, name);
		
		for (Dimension valueDim: values) {
			for (Dimension sourceDim: sources) {
				context.require(//Dimension.getCommonAncestorsOf(values).iterator().next(),
						valueDim,
						sourceDim, targets.iterator().next());
			}
		}
		
		createNodes(graph);
		createEdges(graph);
		
		graph.finish();
				
		return graph;
	}
	
	private void createNodes (final Graph graph) {
		for (Dimension source: sources) {
			graph.addSourceNode(source);
		}
		
		for (Dimension target: targets) {
			graph.addTargetNode(target);
		}
		
		for (Dimension value: values) {
			graph.addValueDimension(value);
		}
		
		graph.createEdges();
	}
	
	private void createEdges (final Graph graph) {
		Filter valueFilter = null;
		for (Dimension valueDimension: values) {
			if (valueFilter == null) {
				valueFilter = Filters.hasDimension(context, valueDimension.getName());
			} else {
				valueFilter = valueFilter.or(Filters.hasDimension(context, valueDimension.getName()));
			}
		}
		
		for (Value value: context.getValues(valueFilter)) {
			Dimension source = value.hasAnyOf(sources);
			Dimension target = value.hasAnyOf(targets);
			if (source != null && target != null) {
				graph.addEdgeValue(source, target, value);
			}
		}
	}
	
	GraphBuilder (final Context context) {
		this.context = context;
	}
	
	public GraphBuilder asTarget() {
		targets = lastDefinitions;
		return this;
	}
	
	public GraphBuilder asSource() {
		sources = lastDefinitions;
		return this;
	}
	
	public GraphBuilder asValues() {
		values = lastDefinitions;
		return this;
	}
	
	public GraphBuilder dimension(Set<Dimension> dimensions) {
		lastDefinitions = dimensions;
		return this;
	}
	
	public GraphBuilder dimension(DimensionCollection collection) {
		return dimension(collection.get());
	}
	
	public GraphBuilder dimension(String dimensionName) {
		return dimension(Sets.newHashSet(context.getDimension(dimensionName)));
	}
	
	private Set<Dimension> lastDefinitions;
}
